package com.xiaoyu.lanling.feature.moment.controller

import `in`.srain.cube.util.StringUtil
import `in`.srain.cube.views.list.CubeRecyclerViewSimpleAdapter
import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.net.Uri
import android.text.Selection
import android.text.TextUtils
import android.util.Pair
import android.view.MenuItem
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import com.xiaoyu.base.app.AppContext
import com.xiaoyu.base.app.GlobalUI
import com.xiaoyu.base.event.AppEventBus
import com.xiaoyu.base.event.SimpleEventHandler
import com.xiaoyu.base.utils.ListUtil
import com.xiaoyu.base.utils.RxUtils
import com.xiaoyu.lanling.R
import com.xiaoyu.lanling.common.Constant
import com.xiaoyu.lanling.event.media.mediaselector.MediaSelectorResultEvent
import com.xiaoyu.lanling.event.moment.publish.*
import com.xiaoyu.lanling.feature.moment.data.PublishData
import com.xiaoyu.lanling.feature.moment.datamodel.FeedBelongType
import com.xiaoyu.lanling.feature.moment.datamodel.PrivacyType
import com.xiaoyu.lanling.feature.moment.datamodel.publish.MediaItemBase
import com.xiaoyu.lanling.feature.moment.viewholder.publish.MomentPublishViewHolderManager
import com.xiaoyu.lanling.feature.prize.PrizeDialogFragment
import com.xiaoyu.lanling.media.selector.MediaSelector
import com.xiaoyu.lanling.media.selector.MediaSelectorFromType
import com.xiaoyu.lanling.media.selector.MediaSelectorType.IMAGE
import com.xiaoyu.lanling.router.Router
import com.xiaoyu.lanling.util.ImageFileCompressUtils
import com.xiaoyu.lanling.view.listener.BaseTextWatcher
import com.zxy.tiny.core.BitmapKit
import kotlinx.android.synthetic.main.moment_publish_activity.*
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.File
import java.util.*
import java.util.regex.Pattern

class PublishViewController(val activity: FragmentActivity) {

    private var mProgressDialog: ProgressDialog? = null
    private var mediaAdapter = CubeRecyclerViewSimpleAdapter<MediaItemBase>()

    private val publishData = PublishData()

    init {
        initView()
        initAdapter()
        initBind()
        initEvent()
        initData()
    }

    fun onSaveInstanceState() {
        publishData.saveDraft()
    }

    fun onDestroy() {
        dismissLoadingProgress()
    }

    fun onDebounceOptionsItemSelected(item: MenuItem?): Any {
        when (item?.itemId) {
            R.id.more -> {
                publish()
                return true
            }
        }
        return false
    }

    private fun invalidateOptionsMenu() {
        activity.invalidateOptionsMenu()
    }

    private fun initView() {
        activity.title = activity.getString(R.string.moment_publish_title)
    }

    private fun initAdapter() {
        mediaAdapter = CubeRecyclerViewSimpleAdapter()
        MomentPublishViewHolderManager.bindViewHolder(mediaAdapter)
        activity.media_recycler_view.adapter = mediaAdapter
    }

    private fun initBind() {
        activity.edit_text.addTextChangedListener(object : BaseTextWatcher() {
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                super.onTextChanged(s, start, before, count)
                if (start == 0) {
                    invalidateOptionsMenu()
                }
                publishData.addText(s.toString())
            }
        })
    }

    private fun initData() {
        val hasDraft = PublishData.hasDraft(FeedBelongType.MOMENT)
        if (hasDraft) {
            restoreDraft()
        } else {
            processIntent()
        }
    }

    private fun processIntent() {
        val mediaPathList = activity.intent.getStringArrayListExtra(Constant.IntentKey.KEY_MOMENT_MEDIA_URL_LIST)
                ?: return
        val original = activity.intent.getBooleanExtra(Constant.IntentKey.KEY_PHOTO_ORIGINAL, false)
        val type = activity.intent.getStringExtra(Constant.PARAM_TYPE)
        when (type) {
            IMAGE -> {
                onMediaAdd(mediaPathList, false, original)
            }
            else -> publishData.notifyPreviewUpdate()
        }
    }

    private fun initEvent() {
        AppEventBus.bindContainerAndHandler(activity, object : SimpleEventHandler() {
            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: AddMediaEvent) {
                openGallery()
            }

            @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
            fun onEvent(event: PreviewListEvent) {
                mediaAdapter.list = event.list
                mediaAdapter.notifyDataSetChanged()
                activity.media_recycler_view.smoothScrollToPosition(mediaAdapter.dataItemCount - 1)
                updateLayoutStatus()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(resultEvent: ResultEvent) {
                dismissLoadingProgress()
                if (resultEvent.isFailed) {
                    return
                }
                activity.finish()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: PreviewPictureClickEvent) {
                if (event.item.position < 0 || publishData.imagePreviewList.isEmpty()) {
                    if (!TextUtils.isEmpty(publishData.videoUri)) {
                        // Router.instance.goToVideoPlayActivity(mActivity, publishData.getVideoUri())
                        return
                    }
                    return
                }
                Router.instance.gotoPhotoActivity(activity, event.item.path, ArrayList(publishData.imagePreviewList))
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: DeletePictureEvent) {
                publishData.removePictureOrVideo(Uri.parse(event.url))
                invalidateOptionsMenu()
            }

            @Subscribe(threadMode = ThreadMode.MAIN)
            fun onEvent(event: MediaSelectorResultEvent) {
                if (event.fromType != MediaSelectorFromType.PUBLISH_MOMENT) {
                    return
                }
                if (event.mediaPathList.isEmpty()) {
                    return
                }
                when (event.type) {
                    IMAGE -> onMediaAdd(event.imagePathList, false, event.original)
                }
            }
        })
    }

    private fun showLoadingProgress(message: String) {
        if (activity.isFinishing || activity.isDestroyed) {
            return
        }
        if (mProgressDialog == null) {
            mProgressDialog = ProgressDialog(activity)
            mProgressDialog?.setMessage(message)
            mProgressDialog?.setCancelable(false)
        }
        mProgressDialog?.show()
    }

    private fun dismissLoadingProgress() {
        if (activity.isFinishing || activity.isDestroyed) {
            return
        }
        if (mProgressDialog?.isShowing == true) {
            mProgressDialog?.dismiss()
        }
    }

    private fun updateLayoutStatus() {
    }

    fun isPublishValid(): Boolean {
        return !publishData.isPublishInvalid
    }

    private fun publish() {
        if (publishData.isPublishInvalid) {
            return
        }
        val text = tryProcessText()
        if (text.isEmpty() && publishData.isOnlyText) {
            return
        }
        showLoadingProgress("正在上传请稍后")
        publishData.publish(text, PrivacyType.PUBLIC)
    }

    private fun tryProcessText(): String {
        // Remove the first and last blank lines
        val paragraphPattern = Pattern.compile("^\\n+|\\n+$|^\\r+|\\r+$")
        val paragraphMatcher = paragraphPattern.matcher(activity.edit_text.text.toString())
        val text = paragraphMatcher.replaceAll("")

        val notEmptyPattern = Pattern.compile("\\s")
        val notEmptyMatcher = notEmptyPattern.matcher(text)
        val notEmptyText = notEmptyMatcher.replaceAll("")

        if (TextUtils.isEmpty(notEmptyText) && publishData.isOnlyText) {
            GlobalUI.getInstance().showToast(activity.getString(R.string.moment_publish_limit_toast))
            return StringUtil.blank()
        }
        return text
    }

    private fun restoreDraft() {
        publishData.restoreDraft()
        restoreText()
    }

    private fun restoreText() {
        activity.edit_text.setText(publishData.text)
        Selection.setSelection(activity.edit_text.text, activity.edit_text.text.length)
    }

    @SuppressLint("CheckResult")
    fun onMediaAdd(mediaPaths: List<String>, isVideo: Boolean, original: Boolean) {
        if (ListUtil.isNullOrEmpty(mediaPaths)) {
            return
        }
        if (isVideo) {
            publishData.addVideo(Uri.fromFile(File(mediaPaths[0])))
            updateLayoutStatus()
            invalidateOptionsMenu()
        } else {
            RxUtils.runOnMainThread { showLoadingProgress(AppContext.getString(R.string.moment_publish_process_dialog)) }
            RxUtils.runOnIOThread {

                // TODO: 2018/9/10 TreeMap better
                val normalImages = ArrayList<String>()
                val longImages = ArrayList<String>()
                for (filePath in mediaPaths) {
                    val pairWidthHeight: Pair<Int, Int>? = getImageWidthHeight(filePath)
                    if (pairWidthHeight != null && pairWidthHeight.first != 0 && pairWidthHeight.second != 0 &&
                            (pairWidthHeight.first / pairWidthHeight.second >= 3 || pairWidthHeight.second / pairWidthHeight.first >= 3)) {
                        longImages.add(filePath)
                    } else {
                        normalImages.add(filePath)
                    }
                }
                if (longImages.isNotEmpty()) {
                    val longPictureUris = ListUtil.convertToList(longImages) { path -> Uri.fromFile(File(path)) }
                    publishData.addPicture(longPictureUris, original)
                    RxUtils.runOnMainThread { updateLayoutAfterMediaAdded() }
                }
                if (normalImages.isNotEmpty()) {
                    if (original) {
                        val pictureUris = ListUtil.convertToList(normalImages) { path -> Uri.fromFile(File(path)) }
                        publishData.addPicture(pictureUris, true)
                        RxUtils.runOnMainThread { updateLayoutAfterMediaAdded() }
                    } else {
                        ImageFileCompressUtils.compressBatchAsFile(normalImages)
                                .filter { paths -> paths.isNotEmpty() }
                                .compose(RxUtils.ioToMainMaybeScheduler())
                                .doFinally { updateLayoutAfterMediaAdded() }
                                .subscribe({ paths ->
                                    val pictureUris = ListUtil.convertToList(paths.toList()) { path -> Uri.fromFile(File(path)) }
                                    publishData.addPicture(pictureUris, false)
                                }, { t -> t.printStackTrace() })
                    }
                }
            }
        }
    }

    private fun updateLayoutAfterMediaAdded() {
        dismissLoadingProgress()
        updateLayoutStatus()
        invalidateOptionsMenu()
    }

    private fun getImageWidthHeight(filePath: String): Pair<Int, Int>? {
        return try {
            BitmapKit.decodeDimensions(filePath)
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    fun onBackPressed() {
        if (publishData.isDraftEmpty) {
            publishData.cleanDraft()
            activity.finish()
        } else {
            AlertDialog.Builder(activity)
                    .setMessage(R.string.moment_publish_save_draft_dialog_message)
                    .setNegativeButton(R.string.moment_publish_save_draft_dialog_negative_button) { _, _ ->
                        publishData.cleanDraft()
                        activity.finish()
                    }
                    .setPositiveButton(R.string.moment_publish_save_draft_dialog_positive_button) { _, _ ->
                        publishData.saveDraft()
                        activity.finish()
                    }.show()
        }
    }

    private fun openGallery() {
        if (publishData.isPictureAdded) {
            val imageAddableCount: Int = publishData.imageAddableCount
            if (imageAddableCount > 0) {
                selectorImage(imageAddableCount)
            }
        } else {
            selectorImage(PublishData.MAX_COUNT_PICTURE)
        }
    }

    private fun selectorImage(maxCount: Int) {
        MediaSelector.instance.selectorForImage(maxCount, true, MediaSelectorFromType.PUBLISH_MOMENT, true)
    }
}